<?php
namespace Core\Libs\Dispatcher;

class DispatcherException {

	
}

class Dispatcher extends \Core\Libs\MasterObject\MasterObject {

	private $arrayRequest = array();
	private static $sanitizeArray = TRUE;
	private static $initRequest = FALSE;
	private static $type = 0;

	final public function dispatch($request = NULL, $arrayConfig = array()) {

		$ReflectionObject = new \Core\Libs\Reflection\ReflectionObject(new \Core\Libs\MasterObject\MasterObject());

		if(!self::$initRequest) {

			$ReflectionObject->getMethod('addObjectInStack')->invoke();
		}

		if(empty($request)) {

			\Core\Libs\Sanitize\Sanitize::sanitizeAllRequests();
			$this->arrayRequest['params']['url'] = \Core\Libs\Url\Url::getUrl($_GET['url']);
		}

		else {

			$request = \Core\Libs\Sanitize\Sanitize::encodeHtmlEntities($request);
			$this->arrayRequest['params']['url'] = \Core\Libs\Url\Url::getUrl($request);
		}

		if(is_array($arrayConfig) && array_key_exists('params', $arrayConfig) && count($arrayConfig['params']) > 0) {

			$mixed = TRUE;

			if(self::$sanitizeArray === TRUE) {

				$arrayConfig['params'] = \Core\Libs\Sanitize\Sanitize::sanitizeArray($arrayConfig['params']);
			}

			else {

				self::$sanitizeArray = TRUE;
			}

			if(is_array($arrayConfig['params']['numeric']) && array_key_exists('numeric', $arrayConfig['params']) && count($arrayConfig['params']['numeric']) > 0) {

				$this->arrayRequest['params']['url']['params']['numeric'] = array_merge($this->arrayRequest['params']['url']['params']['numeric'], (array)$arrayConfig['params']['numeric']);
				unset($arrayConfig['params']['numeric']);
				$mixed = FALSE;
			}

			if(is_array($arrayConfig['params']['assoc']) && array_key_exists('assoc', $arrayConfig['params']) && count($arrayConfig['params']['assoc']) > 0) {

				$this->arrayRequest['params']['url']['params']['assoc'] = array_merge($this->arrayRequest['params']['url']['params']['assoc'], (array)$arrayConfig['params']['assoc']);
				unset($arrayConfig['params']['assoc']);
			}

			elseif($mixed === TRUE && count($arrayConfig['params']) > 0) {

				$this->arrayRequest['params']['url']['params']['assoc'] = array_merge($this->arrayRequest['params']['url']['params']['assoc'], (array)$arrayConfig['params']);
				unset($arrayConfig['params']);
			}
		}

		$this->arrayRequest['requestAction'] = $arrayConfig;
		$Response = parent::getResponse();

		if(isset($_POST['_CoreConfigRequest']['ajax']) && !is_numeric($_POST['_CoreConfigRequest']['ajax'])) {

			throw \Core\Uses\Exception('Error: Valor incorreto para o tipo de requisição.', E_ERROR, 100, __FILE__, __LINE__);
		}

		if(!$Response->RequestHeader()->isAjax() || self::$initRequest) {
	
			if(parent::isCalledByRequestAction()) {

				$arrayReturnType = (array)array_intersect(array('returnOfController', 'responseOfController', 'returnOfView', 'responseOfView', 'responseOfRequest'), (array)$arrayConfig);
				$arrayReturnType = end($arrayReturnType);
		
				if(!empty($arrayReturnType)) {
		
					self::$typeOfResponse = $arrayReturnType;
				}
		
				else {
		
					self::$typeOfResponse = 'responseOfRequest';
				}
	
				$Response->setContentToResponseOfRequest(self::$typeOfResponse);
				$containerType = $Response->getContainerTypeToResponse();
				$typeOfResponse = self::$typeOfResponse;
	
				if(empty($containerType)) {
		
					$Response->setContainerTypeToResponse(self::$typeOfResponse);
				}
		
				if(in_array('sendAll', (array)$arrayConfig)) {
		
					$Response->setAllContentToResponseOfRequest(TRUE);

					ob_start();
				}
		
				else {
		
					$Response->setAllContentToResponseOfRequest(FALSE);
				}
			}

			if(!self::$initRequest) {

				$this->arrayRequest['requestType'] = 0;
			}

			self::$initRequest = FALSE;
			$this->prepare(str_replace('_', '-', $this->arrayRequest['params']['url']['partitioned'][0]));

			if(parent::isCalledByRequestAction()) {

				$responseType = $Response->getContentToResponseOfRequest();

				if($responseType === 'responseOfRequest') {

					if($Response->isAllContentToResponseOfRequest()) {

						parent::setOutputContent(ob_get_clean());
						self::getView()->setOutputContent(NULL);
					}

					else {

						parent::setOutputContent(self::getView()->getOutputContent());
						self::getView()->setOutputContent(NULL);
					}
				}

				else {

					if($responseType === 'responseOfRequest' || $responseType === 'responseOfView' || $responseType === 'returnOfView') {

						parent::setOutputContent(self::getView()->getOutputContent());
						self::getView()->setOutputContent(NULL);
					}

					elseif($responseType === 'responseOfController' || $responseType === 'returnOfController') {

						parent::setOutputContent(self::getController()->getOutputContent());
						self::getController()->setOutputContent(NULL);
					}
				}
			}
		}

		else {

			$_POST = json_decode(file_get_contents('php://input'), TRUE);

			if(empty($_POST)) {

				throw \Core\Uses\Exception('Error: Parametros não enviados para o processamento da requisição.', E_ERROR, 100, __FILE__, __LINE__);
			}
			
			if(strtoupper($_POST['_CoreConfigRequest']['data']['type']) !== 'POST') {

				throw \Core\Uses\Exception('Error: Valor incorreto para o tipo de envio de dados. OBS: SEND ONLY POST', E_ERROR, 100, __FILE__, __LINE__);
			}

			if(empty($_POST['_CoreConfigRequest']['data']['params'])) {

				$arrayParams = array();
			}

			else {

				if(!is_array($_POST['_CoreConfigRequest']['data']['params'])) {

					$arrayParams = (array)$_POST['_CoreConfigRequest']['data']['params'];
				}

				else {

					$arrayParams = $_POST['_CoreConfigRequest']['data']['params'];
				}
			}

			self::$sanitizeArray = FALSE;
			self::$initRequest = TRUE;
			$arrayParams = array('params' => $arrayParams);
			$arrayConfig = array_merge((array)$_POST['_CoreConfigRequest']['data']['options'], (array)$arrayParams);

			if(!in_array('return', $arrayConfig)) {

				$arrayConfig[] = 'return';
			}

			$countRequests = parent::getObjectStack()->count();
			$arrayConfig['requestType'] = 1;
			unset($_POST['_CoreConfigRequest']['ajax'], $arrayParams);

			if($countRequests > 1) {

				parent::getAjaxResponse(TRUE, NULL)->setReadOnly(TRUE);
			}

			$content = \Core\Libs\MasterObject\MasterObject::requestAction($_POST['_CoreConfigRequest']['data']['controller'], $arrayConfig);

			if($countRequests <= 1) {

				$AjaxResponse = parent::getAjaxResponse(TRUE, NULL);
				$AjaxResponse->setEnvResponse(TRUE)->add('response', $content)->setEnvResponse(FALSE);
				$AjaxResponse->send();
				exit(0);
			}
		}

		//if(!parent::isCalledByRequestAction()) {

			$ReflectionObject->getMethod('removeObjectInStack')->invoke();
			parent::getRequest()->prev();
			
		//}
//\core\uses\dump(parent::isCalledByRequestAction());
//\core\uses\dump(parent::getOutputContent());
		return;
	}

	final public function requestNotFound($type = 'controller.class', $redirect = 'pages::errors', $exit = FALSE) {

		$type =& mb_strtolower(&$type);
		$index = 'controllersAndViews';
		$arrayErros = array();
		$arrayParams = array();
		$request = 'controller';
		$message = '';

		if($type === 'controller.class') {

			if($exit === FALSE) {

				
			}

			else {

				$message = 'Erro ao localizar a classe do Controller e/ou seu Namespace.<br>';
				$index = 'controllersAndViews';
				$request = 'controller';
			}

			$showNamespaces = TRUE;
		}

		elseif($type === 'controller.empty') {

			if($exit === FALSE) {

				
			}

			else {

				$message = 'Nenhum Controller foi passado.<br>';
				$index = 'controllersAndViews';
				$request = 'view';
			}

			$showNamespaces = FALSE;
		}

		if($exit === TRUE) {

			if($showNamespaces === TRUE) {

				$message .= 'Namespaces onde foram procurados:<br>';

				foreach($this->arrayRequest['search'][$index] as $i => $arrayErros) {

					$message .= "<br>".'[ '.$i.' ] -> '.$arrayErros[$request]['namespace'];
				}
			}

			throw \Core\Uses\Exception($message, E_ERROR, 100);
		}
	}

	final public function start() {

		if($this->arrayRequest['status']['controller'] === NULL) {

			$this->requestNotFound('controller.empty', NULL, TRUE);
		}

		elseif($this->arrayRequest['status']['controller'] === FALSE) {

			$this->requestNotFound('controller.class', NULL, TRUE);
		}

		$Config =& new \Core\Libs\Extend\Config();
		$RegistryClass =& new \Core\Libs\Registry\RegistryClass();
		$RegistryClass->includeFilesRecursively($this->arrayRequest['controller']['path'], $this->arrayRequest['controller']['namespace'], FALSE);
		$Controller =& new $this->arrayRequest['controller']['namespace']();

		parent::setController($Controller);
		parent::setRegistry($RegistryClass);

		$Controller->_start(&$this->arrayRequest);
	}
	
	final public function prepare($stringRequest = 'paginas') {

		$cSeparator = 0;
		$requestType = 1;
		$arrayRequest = array();
		$arrayNameSpaces = array();
		$arrayPluginsAndModules = array();
		$arrayControllerAndViews = array();
		$arrayNameSpaces['search']['controllersAndViews'] = array();
		$match = array();
		$controllerGenericNameSpace = 'Controllers\\';
		$viewGenericNameSpace = 'Views\\';
		$appName = '';
		$pluginName = '';
		$controllerName = '';
		$cSeparator =& substr_count(&$stringRequest, '.');
		$flagPlugin =& preg_match('/^plugin(s)?/i', &$stringRequest, &$match);
		$flagModule = FALSE;

		if($stringRequest{0} === '.' || $flagPlugin) {

			if($flagPlugin) {

				$match[0] .= '.';
				$arrayRequest =& explode(&$match[0], &$stringRequest, 2);
				$arrayRequest =& explode('.', &$arrayRequest[1]);
			}

			else {

				$arrayRequest =& explode('.', mb_substr(&$stringRequest, 1));
			}

			$requestType = 0;
			$flagModule =& preg_match('/module(s)?/i', &$arrayRequest[1]);
		}

		else {

			$arrayRequest =& explode('.', &$stringRequest);
			$requestType = 1;
		}

		if($cSeparator === 1) {

			list($appName, $controllerName) = $arrayRequest;
			$controllerGenericNameSpace .= $controllerName.'\\'.$controllerName;
			$viewGenericNameSpace .= $controllerName.'\\'.$controllerName;
			$arrayPluginsAndModules =& \Core\Libs\Extend\Config::getActiveModules($appName, $controllerGenericNameSpace);

			$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => '\\'.$appName.'\\', 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\'.$appName.'\\'.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\'.$appName.'\\'.$viewGenericNameSpace), 'path' => NULL));

			if(is_array(&$arrayPluginsAndModules)) {

				foreach($arrayPluginsAndModules as $i => $pluginOrModule) {

					$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => $pluginOrModule, 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$viewGenericNameSpace), 'path' => NULL));
				}
			}
		}

		elseif($cSeparator === 2) {

			if($requestType === 0) {

				list($pluginName, $controllerName) = $arrayRequest;
				$controllerGenericNameSpace .= $controllerName.'\\'.$controllerName;
				$viewGenericNameSpace .= $controllerName.'\\'.$controllerName;

				$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => '\\Plugins\\'.$pluginName.'\\', 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\Plugins\\'.$pluginName.'\\'.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\Plugins\\'.$pluginName.'\\'.$viewGenericNameSpace), 'path' => NULL));
				$arrayPluginsAndModules =& \Core\Libs\Extend\Config::getActiveModules('Plugin.'.$pluginName, $controllerGenericNameSpace);
			}

			if(is_array(&$arrayPluginsAndModules)) {

				foreach($arrayPluginsAndModules as $i => $pluginOrModule) {

					$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => $pluginOrModule, 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule), 'path' => NULL));
				}
			}
		}

		elseif($cSeparator > 2) {

			if($requestType === 0) {

				$pluginName = $arrayRequest[0];
				$moduleName = $arrayRequest[2];
				$controllerName = $arrayRequest[3];
				$controllerGenericNameSpace .= $controllerName.'\\'.$controllerName;
				$viewGenericNameSpace .= $controllerName.'\\'.$controllerName;

				$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\Plugins\\'.$pluginName.'\\Extensions\\Modules\\'.$moduleName.'\\'), 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\Plugins\\'.$pluginName.'\\Extensions\\Modules\\'.$moduleName.'\\'.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\Plugins\\'.$pluginName.'\\Extensions\\Modules\\'.$moduleName.'\\'.$viewGenericNameSpace), 'path' => NULL));
			}

			else {

				$appName = $arrayRequest[0];
				$moduleName = $arrayRequest[2];
				$controllerName = $arrayRequest[3];
				$controllerGenericNameSpace .= $controllerName.'\\'.$controllerName;
				$viewGenericNameSpace .= $controllerName.'\\'.$controllerName;

				$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\'.$appName.'\\Extensions\\Modules\\'.$moduleName.'\\'), 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\'.$appName.'\\Extensions\\Modules\\'.$moduleName.'\\'.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\'.$appName.'\\Extensions\\Modules\\'.$moduleName.'\\'.$viewGenericNameSpace), 'path' => NULL));
			}
		}

		else {

			$controllerName =& $arrayRequest[0];
			$controllerGenericNameSpace .= $controllerName.'\\'.$controllerName;
			$viewGenericNameSpace .= $controllerName.'\\'.$controllerName;

			if($requestType === 0) {

				$arrayPluginsAndModules =& \Core\Libs\Extend\Config::getPluginsAndModulesActives();

				if(is_array(&$arrayPluginsAndModules['plugins'])) {

					foreach($arrayPluginsAndModules['plugins'] as $i => $pluginOrModule) {

						$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => $pluginOrModule, 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$viewGenericNameSpace), 'path' => NULL));
					}
				}
			}

			else {

				$arrayPluginsAndModules[0] =& \Core\Libs\Extend\Config::getPluginsAndModulesActives('Core');

				if($arrayPluginsAndModules[0]['plugins'] !== FALSE) {

					$arrayPluginsAndModules[1] =& \Core\Libs\Extend\Config::getPluginsAndModulesActives(ACTIVE_PROJECT);

					if($arrayPluginsAndModules[1]['plugins'] !== FALSE) {

						$arrayPluginsAndModules['plugins'] =& array_merge(&$arrayPluginsAndModules[0]['plugins'], &$arrayPluginsAndModules[1]['plugins']);
					}

					else {

						$arrayPluginsAndModules['plugins'] =& $arrayPluginsAndModules[0]['plugins'];
					}
				}

				else {

					$arrayPluginsAndModules[1] =& \Core\Libs\Extend\Config::getPluginsAndModulesActives(ACTIVE_PROJECT);

					if($arrayPluginsAndModules[1]['plugins'] !== FALSE) {

						$arrayPluginsAndModules['plugins'] = $arrayPluginsAndModules[1]['plugins'];
					}

					else {

						$arrayPluginsAndModules['plugins'] = array();
					}
				}

				if(is_array(&$arrayPluginsAndModules['plugins'])) {

					foreach($arrayPluginsAndModules['plugins'] as $i => $pluginOrModule) {

						$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => $pluginOrModule, 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$viewGenericNameSpace), 'path' => NULL));
					}
				}

				$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => '\\Core\\', 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\Core\\'.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\Core\\'.$viewGenericNameSpace), 'path' => NULL));

				if(is_array(&$arrayPluginsAndModules[0]['modules'])) {

					foreach($arrayPluginsAndModules[0]['modules'] as $i => $pluginOrModule) {

						$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => $pluginOrModule, 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$viewGenericNameSpace), 'path' => NULL));
					}
				}

				$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => '\\'.ACTIVE_PROJECT.'\\', 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\'.ACTIVE_PROJECT.'\\'.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNamespace('\\'.ACTIVE_PROJECT.'\\'.$viewGenericNameSpace), 'path' => NULL));

				if(is_array(&$arrayPluginsAndModules[1]['modules'])) {

					foreach($arrayPluginsAndModules[1]['modules'] as $i => $pluginOrModule) {

						$arrayNameSpaces['search']['controllersAndViews'][] = array('namespace' => $pluginOrModule, 'controller' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$controllerGenericNameSpace), 'path' => NULL), 'view' => array('namespace' => \Core\Libs\Extend\Config::getNameSpace($pluginOrModule.$viewGenericNameSpace), 'path' => NULL));
					}
				}
			}
		}

		if(empty($controllerName) || (!is_array(&$arrayNameSpaces['search']['controllersAndViews']) || count(&$arrayNameSpaces['search']['controllersAndViews']) < 1)) {

			$arrayNameSpaces['status']['controller'] = NULL;
			$this->start();
		}

		$arrayNameSpaces['status']['controller'] = FALSE;
		$arrayNameSpaces['status']['view'] = FALSE;
		$arrayNameSpacesChecked = array();

		foreach($arrayNameSpaces['search']['controllersAndViews'] as &$arrayControllerAndViews) {

			if(!in_array(&$arrayControllerAndViews['controller']['namespace'], &$arrayNameSpacesChecked)) {

				$arrayControllerAndViews['controller']['path'] =& \Core\Libs\Registry\RegistryClass::getPathOfNamespace($arrayControllerAndViews['controller']['namespace'], NULL, 'default', FALSE);
				$arrayNameSpacesChecked[] = $arrayControllerAndViews['controller']['namespace'];
			}

			if($arrayControllerAndViews['controller']['path'] !== FALSE && $arrayControllerAndViews['controller']['path'] !== NULL) {

				$arrayControllerAndViews['view']['path'] =& \Core\Libs\Registry\RegistryClass::getPathOfNamespace($arrayControllerAndViews['view']['namespace'], NULL, 'default', FALSE);
				$arrayNameSpaces['controller'] =& $arrayControllerAndViews['controller'];
				$arrayNameSpaces['namespace'] =& $arrayControllerAndViews['namespace'];
				$arrayNameSpaces['status']['controller'] = TRUE;

				if($arrayControllerAndViews['view']['path'] !== FALSE) {

					$arrayNameSpaces['view'] =& $arrayControllerAndViews['view'];
					$arrayNameSpaces['status']['view'] = TRUE;
					unset($arrayNameSpaces['search'], $arrayControllerAndViews, $arrayPluginsAndModules, $arrayRequest);
				}

				break;
			}
		}

		unset($arrayNameSpacesChecked, $arrayPluginsAndModules);
		$arrayConfig =& $this->arrayRequest['requestAction'];
		$arrayUrl = array('base' => $this->arrayRequest['params']['url']['base'], 'params' => $this->arrayRequest['params']['url']['params']);
		$action = $this->arrayRequest['params']['url']['partitioned'][1];
		$_requestType = $this->arrayRequest['requestType'];
		$this->arrayRequest =& $arrayNameSpaces;
		$this->arrayRequest['requestAction'] =& $arrayConfig;

		(empty($action)) ? $this->arrayRequest['action'] = 'index' : $this->arrayRequest['action'] =& $action;

		$this->arrayRequest['url'] =& $arrayUrl;
		$this->arrayRequest['requestType'] =& $_requestType;
		$this->start();

		return;
	}
}
?>